import Router from 'koa-router';
import Path from 'path';
import extendContext from './Context';

export default class Component{

    static handler=Symbol();
    static init=extendContext;

    constructor(name,opt={}){
        this.name=name||this.constructor.name;
        this.router=new Router();
        this.children={};
        this.handlerIdentifers=[];
        this.router.name=this.name;
        this.middleware=opt.middleware||[];
        this.preInit();
        this.init();
    }

    preInit(){

    }

    routes(){
        return this.router.routes();
    }

    mount(comp){
        let path="/"+comp.name;
        //console.log(this,path, comp.routes());
        this.router.use(path, comp.routes());
        console.log(this.toString(),"<-",path);
        this.children[comp.name]=comp;
        comp.parent=this;
        comp.onMount();
    }

    onMount(){
        this.printHandlers();
    }

    printHandlers(){
        for (let handler of this.handlerIdentifers){
            console.log(handler.method + " " + Path.join(this.toString(), handler.path).replace(/\\/g, "/"));
        }
    }

    init() {
        let proto=Reflect.getPrototypeOf(this);
        for (let i of Object.getOwnPropertyNames(proto)){
            let handler=proto[i][Component.handler];
            if (handler==null){
                continue;
            }

            let {target, name, verb, path, middleware}=handler;
            path = path || "/" + name + ".do";
            for (let method of verb) {
                this.handlerIdentifers.push({method, path});
                this.router[method](path, ...this.middleware.concat(middleware), async (cx, next) => {
                    try {
                        let data = target[name](cx, next);
                        while (data instanceof Promise) {
                            data = await data;
                        }
                        cx.success(data);
                    } catch (err) {
                        console.error(err);
                        cx.fail(err);
                    }
                })
            }
        }
    }

    toString(){
        return (this.parent?Path.join(this.parent.toString(),this.name):Path.join("/",this.name)).replace(/\\/g,"/");
    }
}
